package com.yuebanmaoshare.file.config.security.filter;

import com.yuebanmaoshare.file.common.exception.NotLoginException;
import com.yuebanmaoshare.file.common.exception.YuebanmaoException;
import com.yuebanmaoshare.file.service.SysParamService;
import com.yuebanmaoshare.file.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    private static final List<String> EXACT_WHITE_LIST = Arrays.asList(
            "/user/register",
            "/user/login",
            "/user/checkuserlogininfo",
            "/filetransfer/downloadfile",
            "/filetransfer/batchDownloadFile",
            "/filetransfer/preview",
            "/share/sharefileList",
            "/share/sharetype",
            "/share/checkextractioncode",
            "/share/checkendtime",
            "/notice/list",
            "/notice/detail",
            "/param/grouplist",
            "/v3/api-docs",
            "/swagger-ui.html",
            "/office/IndexServlet",
            "/doc.html"
    );

    private static final List<String> ANT_WHITE_LIST = Arrays.asList(
            "/*.html",
            "/**/*.html",
            "/**/*.css",
            "/**/*.js",
            "/swagger-ui/**",
            "/webSocket/**",
            "/webjars/**",
            "/swagger-resources/**",
            "/error/**",
            "/v3/api-docs/**"
    );

    @Autowired
    private UserService userService;

    @Resource
    private SysParamService sysParamService;

    @Value("${yuebanmao.file.version}")
    private String yuebanmaoVersion;

    // 添加@NonNull注解解决警告
    @Override
    protected void doFilterInternal(
            @NonNull HttpServletRequest request,
            @NonNull HttpServletResponse response,
            @NonNull FilterChain chain) throws ServletException, IOException {

        // 1. 系统版本检查
        String version = sysParamService.getValue("version");
        if (!yuebanmaoVersion.equals(version)) {
            throw new YuebanmaoException(999999, "脚本未初始化，请在数据库执行数据初始化脚本，存放路径： '/resources/import.sql'！");
        }

        // 2. 检查是否在白名单路径中
        if (isPermittedRequest(request)) {
            chain.doFilter(request, response);
            return;
        }

        // 3. 验证令牌
        String token = request.getHeader("token");
        if (StringUtils.isBlank(token)) {
            throw new NotLoginException("用户未登录");
        }

        // 4. 根据令牌获取用户ID
        String userId = userService.getUserIdByToken(token);
        if (StringUtils.isBlank(userId)) {
            throw new NotLoginException("用户未登录或令牌无效");
        }

        // 5. 设置认证信息
        if (SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = userService.loadUserByUsername(userId);

            // 简化if语句解决警告
            if (!userDetails.isEnabled()) {
                chain.doFilter(request, response);
                return;
            }

            UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(
                            userDetails,
                            null,
                            userDetails.getAuthorities());
            authentication.setDetails(
                    new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        chain.doFilter(request, response);
    }

    /**
     * 检查请求是否在白名单中
     * @param request HTTP请求
     * @return true如果在白名单中，否则false
     */
    private boolean isPermittedRequest(HttpServletRequest request) {
        String uri = request.getRequestURI();
        String method = request.getMethod();

        // 检查精确匹配的白名单
        if (EXACT_WHITE_LIST.contains(uri)) {
            return true;
        }

        // 检查Ant风格的白名单
        for (String pattern : ANT_WHITE_LIST) {
            AntPathRequestMatcher matcher = new AntPathRequestMatcher(pattern);
            if (matcher.matches(request)) {
                return true;
            }
        }

        // 特殊处理Swagger和API文档路径
        return uri.startsWith("/swagger-resources") ||
                uri.startsWith("/webjars/") ||
                uri.startsWith("/v3/api-docs") ||
                // 处理H2控制台路径 (GET请求)
                ("GET".equalsIgnoreCase(method) &&
                        (uri.equals("/h2-console") || uri.startsWith("/h2-console/")));
    }
}